<template>
  <div class="image-editor-container">
    <!-- 顶部操作栏 -->
    <div class="top-bar">
      <span class="editor-title">图片编辑器</span>
      <!-- 在现有模板中添加协同编辑控制按钮 -->
      <div class="collaboration-controls" v-if="isTeamSpace">
        <el-button v-if="canEnterEdit" type="primary" @click="enterEditMode"> 进入编辑 </el-button>
        <el-button v-if="canExitEdit && editingUser" type="warning" @click="exitEditMode">
          退出编辑
        </el-button>
        <el-tag v-if="editingUser" type="info"> 当前编辑者: {{ editingUser.userName }} </el-tag>
      </div>
      <div class="top-actions">
        <el-button class="action-btn" @click="handleDownload" icon="Download">下载图片</el-button>
        <el-button class="action-btn" @click="showSaveDialog = true" icon="UploadFilled"
          >保存到服务器</el-button
        >
      </div>
    </div>

    <div class="main-content">
      <!-- 左侧工具栏 -->
      <div class="left-toolbar">
        <el-upload
          action="#"
          :show-file-list="false"
          :auto-upload="false"
          :on-change="handleUploadChange"
          class="tool-item"
          :disabled="!canEdit"
        >
          <el-tooltip effect="dark" content="上传图片" placement="right">
            <el-icon><PictureFilled /></el-icon>
          </el-tooltip>
        </el-upload>
        <div class="tool-item" @click="showCropDialog = true" :class="{ disabled: !imageSrc }">
          <el-tooltip effect="dark" content="裁剪" placement="right">
            <el-icon><Scissor /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="rotateLeft" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="向左旋转" placement="right">
            <el-icon><RefreshLeft /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="rotateRight" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="向右旋转" placement="right">
            <el-icon><RefreshRight /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="flipX" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="水平翻转" placement="right">
            <el-icon><Switch /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="flipY" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="垂直翻转" placement="right">
            <el-icon style="transform: rotate(90deg)"><Switch /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="addText" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="添加文字" placement="right">
            <el-icon><EditPen /></el-icon>
          </el-tooltip>
        </div>
        <div class="tool-item" @click="toggleStickerPanel" :class="{ disabled: !canEdit }">
          <el-tooltip effect="dark" content="添加贴图" placement="right">
            <el-icon><MagicStick /></el-icon>
          </el-tooltip>
        </div>
      </div>

      <!-- 贴图面板 -->
      <div class="sticker-panel" :class="{ 'is-open': isStickerPanelOpen }">
        <div class="sticker-header">
          <span>选择贴图</span>
          <el-icon @click="isStickerPanelOpen = false" class="close-icon"><Close /></el-icon>
        </div>
        <div class="sticker-grid">
          <img
            v-for="sticker in stickers"
            :key="sticker"
            :src="sticker"
            @click="addSticker(sticker)"
            class="sticker-img"
          />
        </div>
      </div>

      <!-- 中心画布 -->
      <div class="canvas-wrapper" ref="canvasContainer">
        <canvas id="editor-canvas"></canvas>
      </div>

      <!-- 右侧属性/历史面板 -->
      <div class="right-panel">
        <el-tabs v-model="activeTab" class="custom-tabs">
          <el-tab-pane label="属性调整" name="properties">
            <div v-if="activeObject" class="properties-content tab-content-flex">
              <!-- 文字属性 -->
              <div v-if="activeObject.type === 'textbox'" class="property-group">
                <h4 class="prop-title">文字</h4>
                <el-input
                  v-model="textOptions.text"
                  @input="updateText"
                  size="small"
                  :disabled="!canEdit"
                />
                <h4 class="prop-title">颜色</h4>
                <el-color-picker
                  v-model="textOptions.fill"
                  @change="updateText"
                  show-alpha
                  :disabled="!canEdit"
                />
                <h4 class="prop-title">字号</h4>
                <el-slider
                  v-model="textOptions.fontSize"
                  :min="10"
                  :max="120"
                  @input="updateText"
                  size="small"
                  :disabled="!canEdit"
                />
                <h4 class="prop-title">对齐方式</h4>
                <el-radio-group
                  v-model="textOptions.textAlign"
                  @change="updateText"
                  size="small"
                  :disabled="!canEdit"
                >
                  <el-radio-button value="left">居左</el-radio-button>
                  <el-radio-button value="center">居中</el-radio-button>
                  <el-radio-button value="right">居右</el-radio-button>
                </el-radio-group>
              </div>
              <!-- 图片属性 (滤镜) -->
              <div v-if="activeObject.type === 'image'" class="property-group">
                <h4 class="prop-title">色彩调整</h4>
                <div class="filter-item">
                  <span>亮度</span>
                  <el-slider
                    v-model="filterOptions.brightness"
                    :min="-1"
                    :max="1"
                    :step="0.01"
                    @input="applyFilter('brightness')"
                    size="small"
                    :disabled="!canEdit"
                  />
                </div>
                <div class="filter-item">
                  <span>对比度</span>
                  <el-slider
                    v-model="filterOptions.contrast"
                    :min="-1"
                    :max="1"
                    :step="0.01"
                    @input="applyFilter('contrast')"
                    size="small"
                    :disabled="!canEdit"
                  />
                </div>
                <div class="filter-item">
                  <span>饱和度</span>
                  <el-slider
                    v-model="filterOptions.saturation"
                    :min="-1"
                    :max="1"
                    :step="0.01"
                    @input="applyFilter('saturation')"
                    size="small"
                    :disabled="!canEdit"
                  />
                </div>
                <h4 class="prop-title">滤镜</h4>
                <el-radio-group
                  v-model="filterOptions.effect"
                  @change="applyEffectFilter"
                  size="small"
                  class="effect-filters"
                  :disabled="!canEdit"
                >
                  <el-radio-button value="none">原图</el-radio-button>
                  <el-radio-button value="grayscale">黑白</el-radio-button>
                  <el-radio-button value="sepia">复古</el-radio-button>
                  <el-radio-button value="invert">反色</el-radio-button>
                </el-radio-group>
              </div>
            </div>
            <div v-else class="placeholder-text tab-content-flex">
              <p>请先在画布上选择一个元素（图片、文字或贴图）以调整其属性。</p>
            </div>
          </el-tab-pane>

          <el-tab-pane label="操作历史" name="history">
            <div class="history-content tab-content-flex">
              <div class="history-controls">
                <el-button
                  @click="undo"
                  :disabled="historyIndex <= 0 && !canEdit"
                  icon="ArrowLeftBold"
                  size="small"
                  >撤销</el-button
                >
                <el-button
                  @click="redo"
                  :disabled="historyIndex >= history.length - 1 && !canEdit"
                  icon="ArrowRightBold"
                  size="small"
                  >重做</el-button
                >
              </div>
              <ul class="history-list">
                <li
                  v-for="(item, index) in history.slice().reverse()"
                  :key="index"
                  :class="{ 'active-history': history.length - 1 - index === historyIndex }"
                >
                  <span class="history-user" :style="{ color: item.userColor }"
                    >[{{ item.user }}]</span
                  >
                  {{ item.action }}
                </li>
              </ul>
              <!-- 替换原有的硬编码用户列表 -->
              <div class="collaboration-info">
                <h4 class="prop-title">协同创作</h4>
                <div class="user-status-scroll">
                  <!-- 遍历在线用户列表 -->
                  <div class="user-status" v-for="(item, index) in onlineUsers" :key="index">
                    <!-- 状态 dot：在线/离线 -->
                    <span class="status-dot online"></span>
                    <!-- 显示用户名（当前用户标注为"你"） -->
                    <span>
                      {{ item.id === userStore.userInfo.id ? '你' : item.userName }}
                    </span>
                  </div>
                  <!-- 无在线用户时显示提示 -->
                  <div class="user-status" v-if="onlineUsers.length === 0">
                    <span>暂无在线用户</span>
                  </div>
                </div>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>

    <!-- 裁剪弹窗 -->
    <el-dialog
      v-model="showCropDialog"
      title="图片裁剪"
      :close-on-click-modal="false"
      custom-class="crop-dialog"
    >
      <div class="cropper-container">
        <vue-cropper
          ref="cropperRef"
          :img="imageSrc"
          :auto-crop="true"
          :fixed="false"
          :center-box="true"
          output-type="png"
        ></vue-cropper>
      </div>
      <template #footer>
        <el-button @click="showCropDialog = false" class="dialog-btn">取消</el-button>
        <el-button type="primary" @click="confirmCrop" class="dialog-btn primary"
          >确认裁剪</el-button
        >
      </template>
    </el-dialog>

    <!-- 保存到服务器弹窗 -->
    <el-dialog v-model="showSaveDialog" title="保存图片" width="500px">
      <el-form ref="saveFormRef" :model="saveForm" label-width="80px">
        <el-form-item label="图片id">
          <el-input v-model="saveForm.id" placeholder="请输入图片id" disabled></el-input>
        </el-form-item>
        <el-form-item label="空间选择">
          <el-select v-model="saveForm.spaceId" placeholder="请选择空间">
            <el-option label="公共图库" value="null" />
            <el-option
              v-for="item in spaceList"
              :key="item.id"
              :label="item.spaceName"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="图片名称">
          <el-input v-model="saveForm.name" placeholder="请输入图片名称"></el-input>
        </el-form-item>
        <el-form-item label="图片分类">
          <el-select v-model="saveForm.classifyId" placeholder="请选择图片分类">
            <el-option
              v-for="item in classifyStore.classifies"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="图片标签">
          <el-select
            v-model="saveForm.tags"
            multiple
            filterable
            allow-create
            default-first-option
            placeholder="请输入标签"
          />
        </el-form-item>
        <el-form-item label="图片描述">
          <el-input v-model="saveForm.introduction" placeholder="请输入图片描述"></el-input>
        </el-form-item>
      </el-form>
      <template v-slot:footer>
        <el-button @click="showSaveDialog = false">取消</el-button>
        <el-button type="primary" @click="saveImageToServer">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, reactive, computed, onUnmounted, watch } from 'vue'
import { fabric } from 'fabric'
import { VueCropper } from 'vue-cropper'
import 'vue-cropper/dist/index.css'
import { ElMessage } from 'element-plus'
import { uploadPictureAPI, getPictureByIdAPI } from '@/api/pictureAPI'
import { listSpaceByUserIdAPI } from '@/api/spaceAPI'
import { useRoute } from 'vue-router'
import { useClassifyStore } from '@/stores/classify'
import { useUserStore } from '@/stores/user'
import { dataUrlToFile } from '@/utils/dataUrlToFile'
import PictureEditWebSocket from '@/utils/PictureEditWebSocket'
import { PictureEditMessageTypeEnum, PictureEditActionEnum } from '@/types/pictureEdit'

const route = useRoute()
const pictureId = route.query.pictureId
const spaceType = route.query.spaceType

const isTeamSpace = computed(() => {
  return pictureId && spaceType === '1'
})

const classifyStore = useClassifyStore()
const userStore = useUserStore()

// 定义响应式引用和状态变量
const canvasContainer = ref(null) // 画布容器的引用
const cropperRef = ref(null) // 裁剪组件的引用
let fabricCanvas = null // Fabric.js 画布实例

const imageSrc = ref('') // 待裁剪或加载的图片源
const showCropDialog = ref(false) // 控制裁剪弹窗的显示
const showSaveDialog = ref(false) // 控制保存弹窗的显示
const isStickerPanelOpen = ref(false) // 控制贴图面板的显示
const activeTab = ref('properties') // 右侧面板当前激活的标签页

const activeObject = ref(null) // 当前选中的 Fabric.js 对象
const textOptions = reactive({ text: '', fill: '#000000', fontSize: 40, textAlign: 'left' }) // 文字属性
const filterOptions = reactive({ brightness: 0, contrast: 0, saturation: 0, effect: 'none' }) // 滤镜属性

const history = ref([]) // 操作历史记录数组
const historyIndex = ref(-1) // 当前历史记录的索引
let isUpdatingFromHistory = false // 标记是否正在从历史记录恢复状态，避免重复记录

const onlineUsers = ref([]) // 在线用户列表

const saveForm = reactive({
  id: pictureId || null,
  name: '', // 图片名称
  introduction: '', // 图片介绍
  classifyId: null, // 分类ID
  tags: ['编辑', '自定义'], // 图片标签
  spaceId: null, // 空间ID
}) // 保存图片到服务器的表单数据

const spaceList = ref([])

const listSpaceByUserId = async () => {
  if (!userStore.userInfo.id) return
  const res = await listSpaceByUserIdAPI()
  spaceList.value = res.data
}

const getPictureById = async () => {
  console.log('获取图片详情，ID:', pictureId)
  if (!pictureId) return
  const res = await getPictureByIdAPI(pictureId)
  console.log('获取图片详情结果:', res)
  imageSrc.value = res.data.url
  saveForm.classifyId = res.data.classifyId
  saveForm.spaceId = res.data.spaceId
  saveForm.name = res.data.name
  saveForm.introduction = res.data.introduction
  saveForm.tags = res.data.tags

  // 直接加载图片到画布（取消裁剪弹窗）
  loadImageToCanvas(res.data.url, res.data.picWidth, res.data.picHeight)

  updateHistory('上传图片', userStore.userInfo.userName || '未知用户')
}

// 新增图片加载到画布的方法
const loadImageToCanvas = (imageUrl, picWidth, picHeight) => {
  // 创建图片对象获取尺寸（兼容无返回尺寸的情况）
  const img = new Image()
  img.crossOrigin = 'anonymous'
  img.onload = () => {
    // 优先使用接口返回的尺寸，否则使用图片原始尺寸
    const width = picWidth || img.naturalWidth
    const height = picHeight || img.naturalHeight

    // 创建 Fabric 图片对象
    fabric.Image.fromURL(
      imageUrl,
      (oImg) => {
        // 设置图片尺寸为原始尺寸
        oImg.set({
          id: 'mainImage',
          width: width,
          height: height,
          left: fabricCanvas.width / 2, // 居中显示
          top: fabricCanvas.height / 2,
          selectable: true, // 允许选中编辑
        })

        // 清空画布并添加图片
        fabricCanvas.clear()
        fabricCanvas.add(oImg)
        fabricCanvas.setActiveObject(oImg) // 选中图片
        fabricCanvas.renderAll()

        // 发送协同编辑消息
        sendEditAction(PictureEditActionEnum.UPLOAD.value, serializeCanvas())
      },
      { crossOrigin: 'anonymous' },
    )
  }
  img.src = imageUrl
}

// 保存图片到服务
const saveImageToServer = async () => {
  if (!fabricCanvas) return
  if (!imageSrc.value) {
    ElMessage.error('请选择图片')
    return
  }
  // 将画布内容导出为 Data URL
  const dataURL = fabricCanvas.toDataURL({
    format: 'png',
    quality: 1,
  })

  // 将 Data URL 转换为 file 对象
  const file = dataUrlToFile(dataURL, 'image.png')
  console.log(file)
  uploadPictureAPI(file, saveForm).then(() => {
    ElMessage.success('图片保存成功')
    history.value.push('保存图片')
    showSaveDialog.value = false
    listSpaceByUserId()
    updateHistory('保存图片到服务器', userStore.userInfo.userName || '未知用户') // 记录操作
  })
}

onMounted(() => {
  listSpaceByUserId()
  getPictureById()
})

/**
 * 自定义画布对象序列化方法（只保留必要属性）
 * @returns 精简后的画布数据
 */
function serializeCanvas() {
  const mainImage = getImageObject()
  const objects = fabricCanvas.getObjects().map((obj) => {
    const baseProps = {
      type: obj.type,
      id: obj.id,
      left: obj.left,
      top: obj.top,
      angle: obj.angle,
      scaleX: obj.scaleX,
      scaleY: obj.scaleY,
      flipX: obj.flipX,
      flipY: obj.flipY,
      opacity: obj.opacity ?? 1,
      visible: obj.visible ?? true,
    }

    if (obj.type === 'image') {
      return {
        ...baseProps,
        src: obj.id === 'mainImage' ? imageSrc.value : obj._element?.src || '',
        width: obj.width, // 记录图片原始宽度
        height: obj.height, // 记录图片原始高度
        filters: obj.filters?.length
          ? obj.filters.map((filter) => ({
              type: filter.type,
              ...Object.fromEntries(Object.entries(filter).filter(([_, v]) => v != null)),
            }))
          : [],
      }
    } else if (obj.type === 'textbox') {
      return {
        ...baseProps,
        text: obj.text || '',
        fill: obj.fill || '#000000',
        fontSize: obj.fontSize || 40,
        textAlign: obj.textAlign || 'left',
        width: obj.width,
      }
    }
    return baseProps
  })

  return {
    objects,
    // 记录画布当前尺寸
    canvasWidth: fabricCanvas.width,
    canvasHeight: fabricCanvas.height,
    // 记录主图尺寸（用于接收方适配）
    mainImageWidth: mainImage?.width || 0,
    mainImageHeight: mainImage?.height || 0,
  }
}

// 协同编辑
const editingUser = ref(null) // 当前正在编辑的用户
const canEnterEdit = computed(() => {
  return isTeamSpace.value && !editingUser.value
}) // 是否可以进入编辑状态

const canExitEdit = computed(() => {
  return (
    !isTeamSpace.value ||
    (isTeamSpace.value && editingUser.value && editingUser.value.id === userStore.userInfo.id)
  )
}) // 是否可以退出编辑状态

const canEdit = computed(() => {
  return (
    !isTeamSpace.value ||
    (isTeamSpace.value && editingUser.value && editingUser.value.id === userStore.userInfo.id)
  )
})

const webSocket = ref(null) // WebSocket实例
const isConnected = ref(false) // 连接状态

// 初始化WebSocket连接
function initWebSocket() {
  if (isTeamSpace.value && pictureId) {
    webSocket.value = new PictureEditWebSocket(pictureId)
    webSocket.value.connect()

    // 监听连接成功
    webSocket.value.on('open', () => {
      isConnected.value = true
      ElMessage.success('协同编辑连接已建立')
      getOnlineUsers()
    })

    // 监听消息
    webSocket.value.on(PictureEditMessageTypeEnum.ENTER_EDIT.value, (msg) => {
      editingUser.value = msg.user
      ElMessage.info(msg.message)
      getOnlineUsers()
    })

    webSocket.value.on(PictureEditMessageTypeEnum.EXIT_EDIT.value, (msg) => {
      editingUser.value = null
      ElMessage.info(msg.message)
      getOnlineUsers()
    })

    webSocket.value.on(PictureEditMessageTypeEnum.EDIT_ACTION.value, (msg) => {
      // 应用其他用户的编辑操作
      if (msg.data && fabricCanvas) {
        applyRemoteEdit(msg.data)
        ElMessage.info(msg.message)
      }
      getOnlineUsers()
    })

    webSocket.value.on(PictureEditMessageTypeEnum.INFO.value, (msg) => {
      ElMessage.info(msg.message)
      getOnlineUsers()
    })

    webSocket.value.on(PictureEditMessageTypeEnum.ERROR.value, (msg) => {
      ElMessage.error(msg.message)
      getOnlineUsers()
    })
    // 监听用户列表响应
    webSocket.value.on(PictureEditMessageTypeEnum.ONLINE_USERS.value, (msg) => {
      console.log('用户列表响应', msg)

      onlineUsers.value = msg.data // 更新在线用户列表
    })

    // 监听连接关闭
    webSocket.value.on('close', () => {
      isConnected.value = false
      editingUser.value = null
      ElMessage.warning('协同编辑连接已关闭')
    })
  }
}

// 前端请求用户列表
function getOnlineUsers() {
  if (webSocket.value && isConnected.value) {
    webSocket.value.sendMessage({
      type: PictureEditMessageTypeEnum.GET_ONLINE_USERS.value,
    })
  }
}

// 进入编辑模式
function enterEditMode() {
  if (webSocket.value && isConnected.value) {
    webSocket.value.sendMessage({
      type: PictureEditMessageTypeEnum.ENTER_EDIT.value,
    })
  }
}

// 退出编辑模式
function exitEditMode() {
  if (webSocket.value && isConnected.value) {
    webSocket.value.sendMessage({
      type: PictureEditMessageTypeEnum.EXIT_EDIT.value,
    })
  }
}

// 发送编辑操作到服务器
function sendEditAction(action, data) {
  if (canEdit.value && webSocket.value && isConnected.value) {
    webSocket.value.sendMessage({
      type: PictureEditMessageTypeEnum.EDIT_ACTION.value,
      editAction: action,
      data: data,
    })
  }
}

// 应用远程编辑操作
function applyRemoteEdit(data) {
  if (!canEdit.value && fabricCanvas) {
    isUpdatingFromHistory = true
    // 先加载数据
    fabricCanvas.loadFromJSON(
      data,
      () => {
        fabricCanvas.renderAll()
        isUpdatingFromHistory = false
      },
      (o, object) => {
        if (object.type === 'image') {
          object.crossOrigin = 'anonymous'
          if (object.src) {
            object.setSrc(object.src, () => fabricCanvas.renderAll(), {
              crossOrigin: 'anonymous',
            })
          }
        }
      },
    )
    updateHistory(data.message, editingUser.value.userName)
  }
}

// 预设贴图列表
const stickers = [
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f60e.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f496.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f525.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/2b50.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f382.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f4ab.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f4a1.png',
  'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/1f4b0.png',
]

/**
 * 组件挂载后初始化 Fabric.js 画布
 */
onMounted(() => {
  const canvasEl = document.getElementById('editor-canvas')
  fabricCanvas = new fabric.Canvas(canvasEl, {
    backgroundColor: null, // 关键：移除默认背景色（设为透明）
    preserveObjectStacking: true, // 保持对象堆叠顺序
    enableGLFiltering: false, // 禁用 WebGL 滤镜渲染
    enableGLTextures: false, // 禁用 WebGL 纹理
    preferWebGL: false, // 使用 Canvas 渲染
  })

  // 设置所有新创建的 Fabric.js 对象的旋转和缩放中心为对象中心
  fabric.Object.prototype.set({
    originX: 'center',
    originY: 'center',
  })

  /**
   * 调整画布大小以适应其容器
   */
  const resizeCanvas = () => {
    if (canvasContainer.value && fabricCanvas) {
      fabricCanvas.setWidth(canvasContainer.value.clientWidth)
      fabricCanvas.setHeight(canvasContainer.value.clientHeight)
      fabricCanvas.renderAll() // 重新渲染画布
    }
  }

  window.addEventListener('resize', resizeCanvas) // 监听窗口大小变化
  resizeCanvas() // 初始设置画布大小

  updateHistory('初始化画布', '系统') // 记录初始化操作
  // 初始化WebSocket
  initWebSocket()

  // 监听 Fabric.js 画布事件，用于更新操作历史和选中对象
  fabricCanvas.on({
    'object:modified': (e) => {
      const editorUser = editingUser.value
        ? editingUser.value.userName
        : userStore.userInfo.userName
          ? userStore.userInfo.userName
          : '未知用户'
      // 记录操作历史
      updateHistory(
        `修改了 ${e.target.type === 'textbox' ? '文字' : e.target.type === 'image' ? '图片/贴图' : '对象'}`,
        editorUser,
      )
      // 发送协同消息（处理移动、缩放等修改操作）
      if (canEdit.value) {
        // 判断操作类型
        sendEditAction(PictureEditActionEnum.UPDATE.value, serializeCanvas())
      }
    },
    'object:added': (e) => {
      const editorUser = editingUser.value
        ? editingUser.value.userName
        : userStore.userInfo.userName
          ? userStore.userInfo.userName
          : '未知用户'
      updateHistory(
        `添加了 ${e.target.type === 'textbox' ? '文字' : e.target.type === 'image' ? '图片/贴图' : '对象'}`,
        editorUser,
      )
      // 新增元素时发送协同消息
      if (canEdit.value) {
        sendEditAction(PictureEditActionEnum.ADD_ELEMENT.value, serializeCanvas())
      }
    },
    'object:removed': (e) => {
      const editorUser = editingUser.value
        ? editingUser.value.userName
        : userStore.userInfo.userName
          ? userStore.userInfo.userName
          : '未知用户'
      updateHistory(
        `删除了 ${e.target.type === 'textbox' ? '文字' : e.target.type === 'image' ? '图片/贴图' : '对象'}`,
        editorUser,
      )
      // 删除元素时发送协同消息
      if (canEdit.value) {
        sendEditAction(PictureEditActionEnum.DELETE.value, serializeCanvas())
      }
    },
    // 监听文字内容修改
    'text:changed': (e) => {
      const editorUser = editingUser.value
        ? editingUser.value.userName
        : userStore.userInfo.userName
          ? userStore.userInfo.userName
          : '未知用户'
      updateHistory('修改了文字内容', editorUser)
      if (canEdit.value) {
        sendEditAction(PictureEditActionEnum.UPDATE.value, serializeCanvas())
      }
    },
    // 监听画布缩放
    'mouse:wheel': (e) => {
      // 只有滚轮事件导致缩放时才发送（需要判断是否有缩放行为）
      if (e.e.deltaY !== 0 && canEdit.value) {
        // 延迟发送，避免频繁触发
        clearTimeout(window.scaleTimeout)
        window.scaleTimeout = setTimeout(() => {
          sendEditAction(PictureEditActionEnum.SCALE.value, serializeCanvas())
        }, 300)
      }
    },
    'selection:created': updateActiveObject,
    'selection:updated': updateActiveObject,
    'selection:cleared': () => {
      activeObject.value = null
    },
  })
})

/**
 * 更新操作历史记录
 * @param {string} action - 操作描述
 * @param {string} user - 执行操作的用户
 * @param {string} userColor - 用户颜色
 */
function updateHistory(
  action,
  user = userStore.userInfo.userName || '未知用户',
  userColor = '#409EFF',
) {
  if (isUpdatingFromHistory) return // 如果正在从历史记录恢复，则不记录
  const currentState = serializeCanvas() // 获取当前画布状态的 JSON
  // 如果当前历史索引不是最新的，则截断历史记录
  if (historyIndex.value < history.value.length - 1) {
    history.value = history.value.slice(0, historyIndex.value + 1)
  }
  history.value.push({ state: currentState, action, user, userColor }) // 添加新状态到历史记录
  historyIndex.value++ // 更新历史索引
}

/**
 * 撤销上一步操作
 */
function undo() {
  if (!canEdit.value) return
  if (historyIndex.value > 0) {
    isUpdatingFromHistory = true // 标记正在从历史记录恢复
    historyIndex.value-- // 索引回退
    fabricCanvas.loadFromJSON(history.value[historyIndex.value].state, () => {
      fabricCanvas.renderAll() // 重新渲染画布
      isUpdatingFromHistory = false // 恢复完成
      sendEditAction(PictureEditActionEnum.UNDO.value, serializeCanvas())
    })
  }
}

/**
 * 重做下一步操作
 */
function redo() {
  if (!canEdit.value) return
  if (historyIndex.value < history.value.length - 1) {
    isUpdatingFromHistory = true // 标记正在从历史记录恢复
    historyIndex.value++ // 索引前进
    fabricCanvas.loadFromJSON(history.value[historyIndex.value].state, () => {
      fabricCanvas.renderAll() // 重新渲染画布
      isUpdatingFromHistory = false // 恢复完成
      sendEditAction(PictureEditActionEnum.REDO.value, serializeCanvas())
    })
  }
}

/**
 * 处理图片上传文件变化
 * @param {object} file - ElUpload 组件返回的文件对象
 */
function handleUploadChange(file) {
  const reader = new FileReader()
  reader.onload = (e) => {
    imageSrc.value = e.target.result // 设置图片源
    showCropDialog.value = true // 显示裁剪弹窗
  }
  reader.readAsDataURL(file.raw) // 读取文件为 Data URL
}

/**
 * 确认裁剪操作，并将裁剪后的图片加载到 Fabric.js 画布
 */
function confirmCrop() {
  cropperRef.value.getCropData((data) => {
    fabric.Image.fromURL(
      data,
      (img) => {
        // 清空画布
        fabricCanvas.clear()
        // 设置主图位置（左上角对齐，避免居中导致的空白）
        img.set({
          left: img.width / 2, // 基于图片自身尺寸居中
          top: img.height / 2,
          selectable: true,
          hasControls: true,
          hasBorders: true,
          id: 'mainImage',
          originX: 'center',
          originY: 'center',
          height: img.height,
          width: img.width,
        })
        fabricCanvas.add(img)
        fabricCanvas.setActiveObject(img)
        fabricCanvas.renderAll()
        resetFilters()
        updateHistory('裁剪了图片', userStore.userInfo.userName || '未知用户')
        // 发送时携带画布尺寸
        sendEditAction(PictureEditActionEnum.CROP.value, serializeCanvas())
      },
      { crossOrigin: 'anonymous' },
    )
    showCropDialog.value = false
  })
}
/**
 * 更新当前选中的 Fabric.js 对象属性到属性面板
 */
function updateActiveObject() {
  activeObject.value = fabricCanvas.getActiveObject() // 获取当前活动对象
  if (!activeObject.value) return

  // 如果是文字对象，更新文字属性
  if (activeObject.value.type === 'textbox') {
    textOptions.text = activeObject.value.get('text')
    textOptions.fill = activeObject.value.get('fill')
    textOptions.fontSize = activeObject.value.get('fontSize')
    textOptions.textAlign = activeObject.value.get('textAlign')
  } else if (activeObject.value.id === 'mainImage') {
    // 如果是主图片，可以根据需要同步滤镜滑块状态
  }
}

/**
 * 获取当前活动对象，如果未选中则提示
 * @returns {fabric.Object|null} 当前活动对象或null
 */
function getActiveObj() {
  const obj = fabricCanvas.getActiveObject()
  if (!obj) {
    ElMessage.warning('请先选择一个对象') // 提示用户选择对象
    return null
  }
  return obj
}

/**
 * 将当前活动对象向左旋转90度
 */
function rotateLeft() {
  if (!canEdit.value) return
  const obj = getActiveObj()
  if (obj) {
    obj.set('angle', obj.angle - 90).setCoords() // 设置旋转角度并更新坐标
    fabricCanvas.renderAll() // 重新渲染画布
    updateHistory(
      `向左旋转了 ${obj.type === 'textbox' ? '文字' : obj.type === 'image' ? '图片/贴图' : '对象'}`,
      userStore.userInfo.userName || '未知用户',
    ) // 记录操作
    sendEditAction(PictureEditActionEnum.ROTATE.value, serializeCanvas())
  }
}

/**
 * 将当前活动对象向右旋转90度
 */
function rotateRight() {
  if (!canEdit.value) return
  const obj = getActiveObj()
  if (obj) {
    obj.set('angle', obj.angle + 90).setCoords() // 设置旋转角度并更新坐标
    fabricCanvas.renderAll() // 重新渲染画布
    updateHistory(
      `向右旋转了 ${obj.type === 'textbox' ? '文字' : obj.type === 'image' ? '图片/贴图' : '对象'}`,
      userStore.userInfo.userName || '未知用户',
    ) // 记录操作
    sendEditAction(PictureEditActionEnum.ROTATE.value, serializeCanvas())
  }
}

/**
 * 水平翻转当前活动对象
 */
function flipX() {
  if (!canEdit.value) return
  const obj = getActiveObj()
  if (obj) {
    obj.toggle('flipX') // 切换水平翻转状态
    fabricCanvas.renderAll() // 重新渲染画布
    updateHistory(
      `水平翻转了 ${obj.type === 'textbox' ? '文字' : obj.type === 'image' ? '图片/贴图' : '对象'}`,
      userStore.userInfo.userName || '未知用户',
    ) // 记录操作
    sendEditAction(PictureEditActionEnum.FLIP.value, serializeCanvas())
  }
}

/**
 * 垂直翻转当前活动对象
 */
function flipY() {
  if (!canEdit.value) return
  const obj = getActiveObj()
  if (obj) {
    obj.toggle('flipY') // 切换垂直翻转状态
    fabricCanvas.renderAll() // 重新渲染画布
    updateHistory(
      `垂直翻转了 ${obj.type === 'textbox' ? '文字' : obj.type === 'image' ? '图片/贴图' : '对象'}`,
      userStore.userInfo.userName || '未知用户',
    ) // 记录操作
    sendEditAction(PictureEditActionEnum.FLIP.value, serializeCanvas())
  }
}

/**
 * 在画布上添加新的文字对象
 */
function addText() {
  if (!canEdit.value) return
  const text = new fabric.Textbox('双击编辑文字', {
    left: fabricCanvas.getWidth() / 2, // 居中放置
    top: fabricCanvas.getHeight() / 2, // 居中放置
    fontSize: 40,
    fill: '#000000',
    width: 200,
    textAlign: 'center',
    id: `text_${Date.now()}`, // 生成唯一ID
    originX: 'center', // 旋转和缩放中心为对象中心
    originY: 'center',
  })
  fabricCanvas.add(text) // 添加文字到画布
  fabricCanvas.setActiveObject(text) // 设置为活动对象
  updateHistory('添加了文字', userStore.userInfo.userName || '未知用户') // 记录操作
  sendEditAction(PictureEditActionEnum.ADD_ELEMENT.value, serializeCanvas())
}

/**
 * 更新当前选中文字对象的属性
 */
function updateText() {
  if (!canEdit.value) return
  const obj = getActiveObj()
  if (obj && obj.type === 'textbox') {
    obj.set({
      text: textOptions.text,
      fill: textOptions.fill,
      fontSize: textOptions.fontSize,
      textAlign: textOptions.textAlign,
    })
    fabricCanvas.renderAll() // 重新渲染画布
    updateHistory('修改了文字属性', userStore.userInfo.userName || '未知用户') // 记录操作
    sendEditAction(PictureEditActionEnum.UPDATE.value, serializeCanvas())
  }
}

/**
 * 切换贴图面板的显示状态
 */
function toggleStickerPanel() {
  if (!canEdit.value) return
  isStickerPanelOpen.value = !isStickerPanelOpen.value
}

/**
 * 在画布上添加贴图
 * @param {string} url - 贴图的图片URL
 */
function addSticker(url) {
  fabric.Image.fromURL(
    url,
    (img) => {
      img.set({
        left: fabricCanvas.getWidth() / 2, // 居中放置
        top: fabricCanvas.getHeight() / 2, // 居中放置
        scaleX: 0.5, // 初始缩放
        scaleY: 0.5,
        id: `sticker_${Date.now()}`, // 生成唯一ID
        originX: 'center', // 旋转和缩放中心为对象中心
        originY: 'center',
      })
      fabricCanvas.add(img) // 添加贴图到画布
      fabricCanvas.setActiveObject(img) // 设置为活动对象
      updateHistory('添加了贴图', userStore.userInfo.userName || '未知用户') // 记录操作
      sendEditAction(PictureEditActionEnum.ADD_ELEMENT.value, serializeCanvas())
    },
    { crossOrigin: 'anonymous' },
  ) // 允许跨域图片
}

/**
 * 获取画布上的主图片对象
 * @returns {fabric.Image|undefined} 主图片对象
 */
function getImageObject() {
  return fabricCanvas.getObjects('image').find((obj) => obj.id === 'mainImage')
}

/**
 * 应用或更新图片滤镜
 * @param {string} filterType - 滤镜类型 (brightness, contrast, saturation)
 */
function applyFilter(filterType) {
  const image = getImageObject()
  if (!image) return

  // 移除同类型已存在的滤镜
  image.filters = image.filters.filter((f) => f.type.toLowerCase() !== filterType)

  const value = filterOptions[filterType]
  if (value !== 0) {
    // 根据滤镜类型创建新的滤镜实例
    const filterClass = filterType.charAt(0).toUpperCase() + filterType.slice(1)
    const newFilter = new fabric.Image.filters[filterClass]({ [filterType]: value })
    image.filters.push(newFilter) // 添加滤镜
  }

  image.applyFilters() // 应用滤镜到图片
  fabricCanvas.renderAll() // 重新渲染画布
  updateHistory(
    `调整了图片${filterType === 'brightness' ? '亮度' : filterType === 'contrast' ? '对比度' : '饱和度'}`,
    userStore.userInfo.userName || '未知用户',
  ) // 记录操作
  sendEditAction(PictureEditActionEnum.FILTER.value, serializeCanvas())
}

/**
 * 应用或切换效果滤镜 (黑白、复古、反色)
 */
function applyEffectFilter() {
  const image = getImageObject()
  if (!image) return

  // 移除所有效果滤镜
  const effectTypes = ['grayscale', 'sepia', 'invert']
  image.filters = image.filters.filter((f) => !effectTypes.includes(f.type.toLowerCase()))

  const effect = filterOptions.effect
  if (effect !== 'none') {
    // 根据效果类型创建新的滤镜实例
    const filterClass = effect.charAt(0).toUpperCase() + effect.slice(1)
    const newFilter = new fabric.Image.filters[filterClass]()
    image.filters.push(newFilter) // 添加滤镜
  }

  image.applyFilters() // 应用滤镜到图片
  fabricCanvas.renderAll() // 重新渲染画布
  updateHistory(
    `应用了${filterOptions.effect === 'none' ? '原图' : filterOptions.effect === 'grayscale' ? '黑白滤镜' : filterOptions.effect === 'sepia' ? '复古滤镜' : '反色滤镜'}`,
    userStore.userInfo.userName || '未知用户',
  ) // 记录操作
  sendEditAction(PictureEditActionEnum.FILTER.value, serializeCanvas())
}

/**
 * 重置所有滤镜参数
 */
function resetFilters() {
  filterOptions.brightness = 0
  filterOptions.contrast = 0
  filterOptions.saturation = 0
  filterOptions.effect = 'none'
}

/**
 * 下载编辑后的图片
 */
function handleDownload() {
  // 将画布内容导出为 Data URL
  const dataURL = fabricCanvas.toDataURL({
    format: 'png',
    quality: 1,
  })
  const link = document.createElement('a')
  link.href = dataURL
  link.download = 'edited-image.png' // 设置下载文件名
  document.body.appendChild(link)
  link.click() // 触发下载
  document.body.removeChild(link)
  ElMessage.success('图片已开始下载') // 提示用户
  updateHistory('下载了图片', userStore.userInfo.userName || '未知用户') // 记录操作
}

onUnmounted(() => {
  // 组件卸载时关闭WebSocket连接
  if (webSocket.value) {
    exitEditMode()
    webSocket.value.disconnect()
  }
})
</script>

<style scoped>
.image-editor-container {
  width: 100vw;
  height: 100vh;
  background-color: var(--editor-bg);
  color: var(--text-primary);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Top Bar */
.top-bar {
  height: 50px;
  background-color: var(--panel-bg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border-color);
}
.editor-title {
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--text-primary);
}
.top-actions .action-btn {
  background-color: var(--accent-color) !important;
  color: white !important;
  border: none !important;
  transition: background-color 0.3s;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  border-radius: 6px;
}
.action-btn:hover {
  background-color: var(--accent-hover) !important;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

/* Main Content */
.main-content {
  display: flex;
  flex-grow: 1;
  position: relative;
  overflow: hidden;
}

/* Left Toolbar */
.left-toolbar {
  width: 60px;
  background-color: var(--panel-bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 20px;
  flex-shrink: 0;
  z-index: 11;
  border-right: 1px solid var(--border-color); /* Added border for visibility */
}
.tool-item {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-primary);
  cursor: pointer;
  margin-bottom: 15px;
  border-radius: 8px;
  transition:
    background-color 0.2s,
    color 0.2s,
    box-shadow 0.2s;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.tool-item:hover {
  background-color: var(--accent-color);
  color: white;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}
.tool-item.disabled {
  color: var(--text-secondary);
  cursor: not-allowed;
  background-color: transparent;
  box-shadow: none;
}
.tool-item .el-icon {
  font-size: 24px;
}

/* Sticker Panel */
.sticker-panel {
  position: absolute;
  left: 60px;
  top: 0;
  bottom: 0;
  width: 280px;
  background-color: var(--panel-bg);
  transform: translateX(-100%);
  transition: transform 0.3s ease-in-out;
  z-index: 10;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--border-color);
  box-shadow: 2px 0 5px rgba(0, 0, 0, 0.2);
}
.sticker-panel.is-open {
  transform: translateX(0);
}
.sticker-header {
  padding: 15px;
  font-size: 1rem;
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-primary);
}
.close-icon {
  cursor: pointer;
  color: var(--text-secondary);
}
.close-icon:hover {
  color: var(--accent-color);
}
.sticker-grid {
  padding: 15px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
  gap: 10px;
  overflow-y: auto;
}
.sticker-img {
  width: 100%;
  aspect-ratio: 1 / 1; /* 确保正方形宽高比 */
  object-fit: contain; /* 图像在边界内包含 */
  cursor: pointer;
  border-radius: 4px;
  transition:
    transform 0.2s,
    box-shadow 0.2s;
  background-color: var(--editor-bg); /* 贴图的浅色背景 */
  padding: 5px;
  border: 1px solid var(--border-color);
}
.sticker-img:hover {
  transform: scale(1.1);
  box-shadow: 0 0 10px var(--accent-color);
}

/* Canvas Wrapper */
.canvas-wrapper {
  flex-grow: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--canvas-bg); /* Ensure this is white */
  padding: 20px;
  overflow: hidden;
}
#editor-canvas {
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); /* 浅色阴影 */
  border-radius: 8px;
  background-color: var(--canvas-bg); /* 强制画布背景为白色 */
}

/* Right Panel */
.right-panel {
  width: 300px;
  background-color: var(--panel-bg);
  flex-shrink: 0;
  padding: 10px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--border-color); /* Added border for visibility */
}

.custom-tabs {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}

.custom-tabs .el-tabs__header {
  margin-bottom: 15px;
  border-bottom: 1px solid var(--border-color);
}
.custom-tabs .el-tabs__item {
  color: var(--text-secondary);
  font-weight: 500;
}
.custom-tabs .el-tabs__item.is-active {
  color: var(--accent-color);
}
.custom-tabs .el-tabs__active-bar {
  background-color: var(--accent-color);
}
.custom-tabs .el-tabs__nav-wrap::after {
  background-color: transparent; /* 移除默认底线 */
}

.custom-tabs .el-tabs__content {
  flex-grow: 1;
  overflow-y: hidden; /* 标签内容区域内部滚动 */
  padding: 0; /* 移除此处填充，由 tab-content-flex 处理 */
}

.el-tab-pane {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.tab-content-flex {
  flex-grow: 1;
  overflow-y: auto; /* 允许标签内容内部滚动 */
  padding: 0 10px;
  display: flex;
  flex-direction: column;
}

.property-group {
  margin-bottom: 20px;
  padding-bottom: 10px;
  border-bottom: 1px dashed var(--border-color);
}
.property-group:last-child {
  border-bottom: none;
}
.prop-title {
  font-size: 0.9rem;
  font-weight: 600;
  margin: 15px 0 8px 0;
  color: var(--text-primary);
}

.filter-item {
  margin-bottom: 10px;
}
.filter-item span {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.placeholder-text {
  padding: 20px;
  text-align: center;
  color: var(--text-secondary);
  font-size: 0.9rem;
}

/* History */
.history-controls {
  display: flex;
  justify-content: space-between;
  margin-bottom: 15px;
  flex-shrink: 0; /* 防止控件收缩 */
}
.history-list {
  flex-grow: 1; /* 允许占据可用空间 */
  overflow-y: auto; /* 启用列表滚动 */
  list-style: none;
  padding: 0;
  margin: 0;
  margin-bottom: 15px; /* 协同信息上方空间 */
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background-color: var(--editor-bg);
}
.history-list li {
  padding: 8px 12px;
  margin-bottom: 2px; /* 项目间距 */
  border-radius: 4px;
  font-size: 0.85rem;
  color: var(--text-primary);
  background-color: transparent; /* 单个项目无背景 */
  transition: background-color 0.2s;
}
.history-list li:hover {
  background-color: rgba(0, 191, 255, 0.1); /* 浅蓝色悬停 */
}
.history-list li.active-history {
  background-color: var(--accent-color);
  color: white;
}
.history-user {
  font-weight: 600;
  margin-right: 5px;
}

/* Collaboration Info */
.collaboration-info {
  margin-top: 10px;
  border-top: 1px solid var(--border-color);
  padding-top: 15px;
  flex-shrink: 0;
}
.user-status-scroll {
  max-height: 150px; /* 限制高度以实现滚动 */
  overflow-y: auto;
  padding-right: 5px; /* 滚动条空间 */
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 10px;
  background-color: var(--editor-bg);
}
.user-status {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
  font-size: 0.9rem;
  color: var(--text-primary);
}
.user-status:last-child {
  margin-bottom: 0;
}
.status-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
}
.status-dot.online {
  background-color: #32cd32; /* LimeGreen */
}
.status-dot.offline {
  background-color: #a9a9a9; /* DarkGray */
}

/* Custom Element Plus Components */
.el-slider__bar {
  background-color: var(--accent-color) !important;
}
.el-slider__button {
  border-color: var(--accent-color) !important;
  background-color: white !important;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.el-radio-button__inner {
  background-color: var(--editor-bg);
  border-color: var(--border-color) !important;
  color: var(--text-secondary);
  box-shadow: none !important;
  transition:
    background-color 0.2s,
    color 0.2s;
}
.el-radio-button__inner:hover {
  color: var(--accent-color);
}
.el-radio-button__original-radio:checked + .el-radio-button__inner {
  background-color: var(--accent-color);
  color: white;
  border-color: var(--accent-color) !important;
}
.effect-filters .el-radio-button {
  margin-right: 5px;
  margin-bottom: 5px;
}

/* Dialogs */
.crop-dialog,
.save-dialog {
  background-color: var(--panel-bg) !important;
  border-radius: 8px;
  max-width: 800px;
  width: 90%;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.crop-dialog .el-dialog__title,
.save-dialog .el-dialog__title {
  color: var(--text-primary);
  font-weight: 600;
}
.crop-dialog .el-dialog__headerbtn .el-dialog__close,
.save-dialog .el-dialog__headerbtn .el-dialog__close {
  color: var(--text-secondary);
}
.crop-dialog .el-dialog__headerbtn .el-dialog__close:hover {
  color: var(--accent-color);
}
.cropper-container {
  width: 100%;
  height: 50vh;
  min-height: 200px; /* 确保裁剪器有最小高度 */
  background-color: #f0f0f0; /* 裁剪区域的浅色背景 */
  border-radius: 4px;
}
.dialog-btn {
  background-color: var(--editor-bg) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-color) !important;
  border-radius: 6px;
  transition:
    background-color 0.2s,
    color 0.2s,
    border-color 0.2s;
}
.dialog-btn:hover {
  background-color: var(--accent-hover) !important;
  color: white !important;
  border-color: var(--accent-hover) !important;
}
.dialog-btn.primary {
  background-color: var(--accent-color) !important;
  border-color: var(--accent-color) !important;
  color: white !important;
}
.dialog-btn.primary:hover {
  background-color: var(--accent-hover) !important;
  border-color: var(--accent-hover) !important;
}

/* Form in Dialog */
.save-dialog .el-form-item__label {
  color: var(--text-secondary);
}
.save-dialog .el-input__wrapper,
.save-dialog .el-select__wrapper {
  background-color: var(--editor-bg) !important;
  box-shadow: none !important;
  border: 1px solid var(--border-color);
  border-radius: 6px;
}
.save-dialog .el-input__inner,
.save-dialog .el-select__placeholder {
  color: var(--text-primary);
}

.el-select-dropdown {
  background-color: var(--editor-bg) !important;
  border-color: var(--border-color) !important;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.el-select-dropdown__item {
  color: var(--text-primary);
}
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover {
  background-color: var(--accent-color) !important;
  color: white !important;
}
/* 画布禁用状态 */
.canvas-disabled {
  pointer-events: none;
  filter: blur(2px) grayscale(0.5);
  cursor: not-allowed !important; /* 强化鼠标不可用提示 */
}
</style>
